﻿#region using statements

using System.Collections.Generic;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using NGen.Managers.Logging;

#endregion

namespace NGen.Managers.Particle
{

	public class ManagerParticles : GameManager, IManagerParticles
	{
		#region local fields

		/// <summary>
		/// a list of the dead particle systems waiting to be destroyed
		/// </summary>
		protected List<ParticleSystem> m_lDeadParticleSystems = new List<ParticleSystem>();

		/// <summary>
		/// a list of the particle systems waiting to be added
		/// </summary>
		protected List<ParticleSystem> m_lNewParticleSystems = new List<ParticleSystem>();

		/// <summary>
		/// a list of all active particle systems
		/// </summary>
		protected List<ParticleSystem> m_lParticleSystems = new List<ParticleSystem>();

		#endregion

		#region constructors

		/// <summary>
		/// construct a new particle manager
		/// </summary>
		public ManagerParticles() {
			Logger = GameEngine.GetService<IManagerLogs>().Log<ManagerParticles>();
			CurrentLoggingLevel = LoggingLevel.MINIMAL;
			SkipUpdate = false;
			SkipDraw = false;
			UpdateOrder = 1;
			DrawOrder = 300;
		}

		#endregion

		#region GameManager implementation

		/// <summary>
		/// initialize the manager
		/// </summary>
		internal override void Initialize() {
			TransformMatrix = Tools.TransformMatrix.CreateDefault();
		}

		/// <summary>
		/// update the manager
		/// </summary>
		/// <param name="p_gameTime">snapshot of timing values</param>
		internal override void Update(GameTime p_gameTime) {
			foreach(var system in m_lDeadParticleSystems) {
				if(m_lParticleSystems.Contains(system)) {
					m_lParticleSystems.Remove(system);
				}
			}
			m_lDeadParticleSystems.Clear();

			m_lParticleSystems.AddRange(m_lNewParticleSystems);
			m_lNewParticleSystems.Clear();

			foreach(var system in m_lParticleSystems) {
				system.Update(p_gameTime);
			}
		}

		/// <summary>
		/// draw the manager
		/// </summary>
		/// <param name="p_gameTime">snapshot of timing values</param>
		internal override void Draw(GameTime p_gameTime) {
			GameEngine.SpriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, null, null, null, TransformMatrix);

			foreach(var system in m_lParticleSystems) {
				system.Draw(GameEngine.SpriteBatch);
			}

			GameEngine.SpriteBatch.End();
		}

		/// <summary>
		/// cleanup the manager
		/// </summary>
		internal override void Cleanup() {
			DestroyAllParticleSystems();
		}

		#endregion

		#region IManagerParticles implementation


		/// <summary>
		/// get or set the transform matrix used by the spritebatch to scroll the sprites on the screen
		/// </summary>
		public Matrix TransformMatrix { get; set; }

		public void AddParticleSystem(ParticleSystem p_system) {
			m_lNewParticleSystems.Add(p_system);
		}

		/// <summary>
		/// destroy the specified particle system
		/// </summary>
		/// <param name="p_system">the particle system to destroy</param>
		public void DestroyParticleSystem(ParticleSystem p_system) {
			m_lDeadParticleSystems.Add(p_system);
		}

		/// <summary>
		/// destroys all active particle systems
		/// </summary>
		public void DestroyAllParticleSystems() {
			m_lDeadParticleSystems.AddRange(m_lParticleSystems);
			m_lDeadParticleSystems.AddRange(m_lNewParticleSystems);

			m_lParticleSystems.Clear();
			m_lNewParticleSystems.Clear();
		}

		#endregion
	}

	public interface IManagerParticles : IGameManager
	{
		/// <summary>
		/// get or set the transform matrix used by the spritebatch to scroll the sprites on the screen
		/// </summary>
		Matrix TransformMatrix { get; set; }

		/// <summary>
		/// destroy the specified particle system
		/// </summary>
		/// <param name="p_system">the particle system to destroy</param>
		void AddParticleSystem(ParticleSystem p_system);

		/// <summary>
		/// destroy the specified particle system
		/// </summary>
		/// <param name="p_system">the particle system to destroy</param>
		void DestroyParticleSystem(ParticleSystem p_system);

		/// <summary>
		/// destroys all active particle systems
		/// </summary>
		void DestroyAllParticleSystems();
	}
}